#!/usr/bin/python
# vim: set fileencoding=utf8 :

import glob,sys,os,re
from pylab import *
import tables
from PIL import Image
import ImageFont,ImageDraw
from scipy.ndimage import filters,measurements
from ocrolib import ligatures,docproc
from ocrolib.ocroio import renumber_labels
from llpy.sutils import *
import traceback

import argparse
parser = argparse.ArgumentParser(description = "Generate data")
parser.add_argument('-o','--output',default="fontgen.h5",help="output file")
parser.add_argument('-k','--kind',default="ligatures",help='characters to generate')
parser.add_argument('-d','--display',default=None,help="select a class for progress reporting")
parser.add_argument('-D','--debug_show',default=None,help="select a class for stepping through")
parser.add_argument('-N','--nsamples',default=999999999,help="max number of samples",type=int)
args = parser.parse_args()

fonts = """AmericanTypewriter.ttf AmericanTypewriterBold.ttf
AmericanTypewriterCondensed.ttf AmericanTypewriterCondensedBold.ttf
AmericanTypewriterCondensedLight.ttf AmericanTypewriterLight.ttf
BodoniSvtyTwoITCTTBold.ttf BodoniSvtyTwoITCTTBook.ttf
BodoniSvtyTwoITCTTBookIta.ttf BodoniSvtyTwoOSITCTTBold.ttf
BodoniSvtyTwoOSITCTTBook.ttf BodoniSvtyTwoOSITCTTBookIt.ttf
Chalkboard.ttf ChalkboardBold.ttf
DidotBold.ttf DidotItalic.ttf GenevaCY.ttf Georgia.ttf GeorgiaBold.ttf
GeorgiaBoldItalic.ttf GeorgiaItalic.ttf GillSans.ttf GillSansBold.ttf
GillSansBoldItalic.ttf GillSansItalic.ttf GillSansLight.ttf
GillSansLightItalic.ttf HelveticaNeue.ttf HelveticaNeueBold.ttf
HelveticaNeueBoldItalic.ttf HelveticaNeueCondensedBlack.ttf
HelveticaNeueCondensedBold.ttf HelveticaNeueItalic.ttf
HelveticaNeueLight.ttf HelveticaNeueLightItalic.ttf
HelveticaNeueUltraLight.ttf HelveticaNeueUltraLightItalic.ttf
OptimaBold.ttf OptimaBoldItalic.ttf OptimaExtraBlack.ttf OptimaItalic.ttf
OptimaRegular.ttf Palatino.ttf PalatinoBold.ttf PalatinoBoldItalic.ttf
PalatinoItalic.ttf SkiaRegular.ttf StoneSansITCTTBold.ttf
StoneSansSemITCTTSemi.ttf StoneSansSemITCTTSemiIta.ttf Vera.ttf VeraBI.ttf
VeraBd.ttf VeraIt.ttf VeraMoBI.ttf VeraMoBd.ttf VeraMoIt.ttf VeraMono.ttf
VeraSe.ttf VeraSeBd.ttf arial.ttf arialbd.ttf arialbi.ttf
ariali.ttf ariblk.ttf comic.ttf comicbd.ttf cour.ttf courbd.ttf courbi.ttf
couri.ttf framd.ttf framdit.ttf georgia.ttf georgiab.ttf georgiai.ttf
georgiaz.ttf impact.ttf kartika.ttf l_10646.ttf lucon.ttf micross.ttf
pala.ttf palab.ttf palabi.ttf palai.ttf tahoma.ttf tahomabd.ttf times.ttf
timesbd.ttf timesbi.ttf timesi.ttf trebuc.ttf trebucbd.ttf trebucbi.ttf
trebucit.ttf verdana.ttf verdanab.ttf verdanai.ttf verdanaz.ttf
vrinda.ttf""".split()

common_ligature_table = """
00 La Th ac ai ak al all am an ar as at be bo bj ca ch co ct
di dr ea ec ed ee el em en er es fa fe ff ffi fl fo fr ft fu
gh gi gn gr gu he hi il
in ir is ki la le li lo ll ls ly ma me mi mm mo nd ng ni ns
oc od of om on oo or ow pe po ra re rf ri rin 
rm rn ro rr rs rt ru rv ry sa se sl so ss st ta te th ti tl to tr
ts tt tu ty ul um un ur ve vi wi wn
""".split()

more_chars = u"""
æ œ ﬀ ﬁ ﬂ ﬃ  ﬄ  ﬅ ﬆ
ä ö ü Ä Ö Ü ß é É 
¢ £ ¥ § © ® ° ‘ ’ “ ” „ 
◼ ▶ ◻ ▷ ○ ◊ 
""".split()

weird = """
a. c. e. m. n. t. z. A. C. E. K. L. M. N. R.
a, c, e, m, n, t, z, A, C, E, K, L, M, N, R,
"B "D "F "H "K "L "P "R "T "W "Z "b "h "l
'B 'D 'F 'H 'K 'L 'P 'R 'T 'W 'Z 'b 'h 'l
d" f" l" 
a- b- e- d- g- m- n- o- p- u-
""".split()


# """SnellRoundhand.ttf Copperplate.ttf CopperplateBold.ttf CopperplateLight.ttf"""

fontdir = "/home/tmb/bin/Fonts/"

csize = 32

fontfiles = [fontdir+f for f in fonts]

chars = [chr(x) for x in range(33,126)]
if args.kind=="ligatures":
    chars += common_ligature_table 
ion(); gray()

def sigmathresholds():
    return [
    (0.0,0.4+rand()*0.2),
    (0.4+rand()*0.2,0.5),
    (0.5+rand()*0.2,0.6),
    (0.6+rand()*0.2,0.7),
    (0.4+rand()*0.2,0.5),
    (0.5+rand()*0.2,0.6),
    (0.6+rand()*0.2,0.7),
    (0.6+rand()*0.2,0.8),
    (0.9+rand()*0.2,0.4),
    (0.9+rand()*0.2,0.5),
    (0.9+rand()*0.2,0.4),
    (0.9+rand()*0.2,0.5),
    (0.9+rand()*0.2,0.6),
    ]

def rgeometry(image,eps=0.03,delta=0.3):
    m = array([[1+eps*randn(),eps*randn()],[eps*randn(),1.0+eps*randn()]])
    w,h = image.shape
    c = array([w/2.0,h/2])
    d = c-dot(m,c)+array([randn()*delta,randn()*delta])
    return interpolation.affine_transform(image,m,offset=d,order=1)

compute_lgeo = 1

def line_context():
    return "The quick brown Fox jumped over the Lazy Dogs."

def bounding_box(a):
    a = array(a>0,'i')
    l = measurements.find_objects(a)
    if len(l)<1: return (0,0,0,0)
    ys,xs = l[0]
    # y0,x0,y1,x1
    return (ys.start,xs.start,ys.stop,xs.stop)

import ocrolseg
char_segmenter = ocrolseg.SegmentLineByGCCS()

def charseg(image):
    return char_segmenter.charseg(image)

with tables.openFile(args.output,"w") as odb:
    odb.createEArray(odb.root,"patches",tables.Float32Atom(),shape=[0,csize,csize],filters=tables.Filters(9))
    odb.createEArray(odb.root,"classes",tables.Int64Atom(),shape=(0,),filters=tables.Filters(9))
    if compute_lgeo:
        odb.createEArray(odb.root,"rel",tables.Float32Atom((3,)),shape=(0,),filters=tables.Filters(9))
    for fontfile in fontfiles:
        for size in [36,48,64,96]:
            font = ImageFont.truetype(fontfile,size)
            image = Image.new("L",(3000,100))
            draw = ImageDraw.Draw(image)
            for (sigma,threshold) in sigmathresholds():
                print "===",fontfile,sigma,threshold
                for cls in chars:
                    try:
                        rel = None
                        debug_show = (cls==args.debug_show)
                        if compute_lgeo:
                            # for getting the line geometry, we first render the string without
                            # context to get its width and then render it with context
                            draw.rectangle((0,0,3000,3000),fill="black")
                            draw.text((10,10),cls,font=font,fill="white")
                            b = bounding_box(asarray(image))
                            (y0,x0,y1,x1) = b
                            # print "bbox",b
                            # ion(); clf(); gray(); imshow(asarray(image)[:100,:100]); title("no context"); ginput(1,10000)
                            cls_width = x1+5
                        draw.rectangle((0,0,3000,3000),fill="black")
                        draw.text((10,10),cls+"  "+line_context(),font=font,fill="white")
                        a = asarray(image)
                        a = filters.gaussian_filter(a,sigma)
                        a += clip(randn(*a.shape)*0.2,-0.25,0.25)
                        a = array(a>threshold,'f')
                        if amax(a)<0.1: continue
                        if compute_lgeo:
                            line = a
                            rseg = charseg(1-1*(line>0.5*amax(line)))
                            rseg = renumber_labels(rseg,1)
                            if debug_show:
                                print "geo",geo
                                ion(); clf(); gray(); imshow(rseg[:,:300]); title("segmentation");
                                ch,lm,lb = geo; plot([0,300],[h-lb,h-lb-lm*300]); ginput(1,10000)
                            geo = docproc.seg_geometry(rseg)
                            a = asarray(image)
                            h,w = a.shape
                            if debug_show:
                                print "geo",geo
                                ion(); clf(); gray(); imshow(a[:,:300]); title("line geometry on grayscale");
                                ch,lm,lb = geo; plot([0,300],[h-lb,h-lb-lm*300]); ginput(1,10000)
                            a = a[:,:cls_width]
                            if debug_show:
                                ion(); clf(); gray(); imshow(a[:100,:100]); title("cut out image"); ginput(1,10000)
                            bb = bounding_box(a>0.5*amax(a))
                            (y0,x0,y1,x1) = bb
                            bb = (h-y1-1,h-y0-1,x0,x1)
                            try:
                                rel = docproc.rel_char_geom(bb,geo)
                            except:
                                print "rel_char_geom failed for",fontfile,size,cls
                                traceback.print_exc()
                                continue
                            ry,rw,rh = rel
                            rel = (-ry,rw,rh) # somehow the sign got flipped above
                            # rel = docproc.rel_geo_normalize(rel)
                            # print "rel",rel,geo
                        a = docproc.isotropic_rescale(a,csize)
                        a = rgeometry(a)
                        a = csnormalize(a)
                        if debug_show:
                            print a.shape,bb,rel,geo
                            clf(); imshow(a); ginput(1,10000)
                        if cls==args.display:
                            print "rel",rel
                            clf(); imshow(a); ginput(1,0.001)
                        a = a*1.0/amax(a)
                        odb.root.patches.append([a])
                        odb.root.classes.append([uencode(cls)])
                        if compute_lgeo:
                            odb.root.rel.append([array(rel,'f')])
                    except:
                        traceback.print_exc()
                if len(odb.root.classes)>=args.nsamples: sys.exit(0)
